package com.util;

import java.io.UnsupportedEncodingException;
import org.json.JSONArray;
import org.json.JSONObject;

import com.config.ConstDefine;
/**
 * 各地图API坐标转换;
 * WGS84坐标系：国际上通用的坐标系;
 * GCJ02坐标系：即火星坐标系。 (高德、腾讯地图等) 
 * BD-09： 百度坐标系 百度 
 */
public class PositionUtil {
	
	public static final String BAIDU_LBS_TYPE = "bd09ll";
	
	public static double pi = 3.1415926535897932384626;
	public static double a = 6378245.0;
	public static double ee = 0.00669342162296594323;
 
	public static void main(String[] args) {
//		System.out.println(pointSerch("拓", "拓城县"));
//		Gps g=gcj02_To_Bd09(126.69489531, 45.69386881);
//		System.out.println("point:"+g.getLatitude()+","+g.getLontitude());
//		System.out.println(point2addr("45.75702162427602,126.66523437709809"));
		
		//JSONObject json=point2addr("126.66523437709809,45.75702162427602");
//		System.out.println(json.toString());
//		JSONObject json= pointSerch_gd("福泰名苑", "哈尔滨市", "");
//		System.out.println(json.toString());
		

//		JSONObject json= point2addr("45.747744,126.64933");
//		System.out.println(json.toString());
//		System.out.println(getADD("哈尔滨市哈尔滨市香坊区进乡街55号福泰名苑13栋2单元101-2号"));
		
		System.out.println(gps84_To_Gcj02(126.69489531+","+45.69386881));
		
//		Gps g=bd09_To_Gps84(126.707331,45.702696);
//		System.out.println("point:"+g.getLatitude()+","+g.getLontitude());
		
	}
	/**
	 * 将给定坐标XY互换
	 * @param point
	 */
	public static String changeXY(String point)
	{
		System.out.println("point is :"+point);
		if(StrKit.notBlank(point)&&point.contains(","))
		{
			String[] points=point.split(",");
			return points[1]+","+points[0];
		}else{
			return "";
		}
	}
	
	/**
	 * 高德逆地址解析，获取地市、当前上车点，附近的点
	 * @param point
	 * @return
	 */
	public static JSONObject point2addr(String point)
	{
		//转型POINT
		String[] points=point.split(",");
		point=points[1].trim()+","+points[0].trim();
		JSONObject jsonres=null;
		String url="https://restapi.amap.com/v3/geocode/regeo?key="+ConstDefine.gaodeKey+
				"&location="+point+
				"&radius=1000"+
				"&roadlevel=1"+
				"&extensions=all"+
				"&batch=false";
		String res=HttpKit.get(url);
		System.out.println(res);
		JSONObject json=new JSONObject(res);
		if(json.getJSONObject("regeocode").getJSONObject("addressComponent")!=null)
		{
			jsonres=new JSONObject();
			JSONObject json_city=json.getJSONObject("regeocode").getJSONObject("addressComponent");
			jsonres.put("code", "00");
			jsonres.put("province", json_city.get("province"));
			jsonres.put("city", json_city.get("city"));
			jsonres.put("area", json_city.get("district"));
			if( json.getJSONObject("regeocode").getJSONArray("pois")!=null)//查询到了POI
			{
				JSONObject json_aois=(JSONObject) json.getJSONObject("regeocode").getJSONArray("pois").get(0);
				jsonres.put("addr", json_aois.get("name"));
			}
		}
		
		return jsonres;
	}
	
	/**
	 * 根据本机请求IP获取地市-------停用
	 * @return
	 */
	public static JSONObject getCityByIp()
	{
		JSONObject json_res=new JSONObject();
		StringBuffer sb=new StringBuffer("http://api.map.baidu.com/location/ip?coor=bd09ll");
		sb.append("&ak="+ConstDefine.getBaiduAK());
//		sb.append("&callback=showLocation");
		String res=HttpKit.get(sb.toString());
		System.out.println(res);
		JSONObject json=new JSONObject(res);
		if(json.getInt("status")==0){
			JSONObject point=json.getJSONObject("content").getJSONObject("point");
			JSONObject address_detail=json.getJSONObject("content").getJSONObject("address_detail");
			json_res.put("province", address_detail.getString("province"));
			json_res.put("city", address_detail.getString("city"));
			json_res.put("lat", point.getString("y"));
			json_res.put("lng", point.getString("x"));
			json_res.put("returnCode", "00");
		}
		
		
		return json_res;
	}
	/**
	 * @Title: getADD   
	 * @Description: TODO(高德 根据地址获取坐标)
	 * @date:2019年12月4日 下午2:19:45 
	 * @author: lch
	 */
	public static String getADD(String add){
		String queryUrl = "http://restapi.amap.com/v3/geocode/geo?key="+ConstDefine.gaodeKey+"&address="+add;
		String queryResult = HttpKit.get(queryUrl);; //高德接品返回的是JSON格式的字符串
		try {
			JSONObject json=new JSONObject(queryResult);
			JSONArray object = (JSONArray) json.get("geocodes");
			if(object!=null && object.length()>0){
				JSONObject j2 = object.getJSONObject(0);
				return j2.getString("location");
			}else{
				return "";
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}
	
	/**
	 * 根据关键字查询该城市地标----高德
	 * @param areaName
	 * @param city
	 * @return
	 */
	public static JSONObject pointSerch_gd(String areaName,String city,String types)
	{
		StringBuffer sb=new StringBuffer("https://restapi.amap.com/v3/place/text?key="+ConstDefine.gaodeKey);
		if(StrKit.notBlank(areaName))sb.append("&keywords="+areaName);
		if(StrKit.notBlank(types))sb.append("&types="+types);
		sb.append("&city="+city);
		sb.append("&offset=10");
		sb.append("&page=1");
		sb.append("&extensions=all");
		String req="";
		try {
			req=new String(sb.toString().getBytes("utf-8"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String res=HttpKit.get(req);
//		System.out.println("高德请求："+req);
//		System.out.println("高德返回："+res);
		JSONObject json=new JSONObject(res);
		if(json.getString("status").equals("1")&&json.getString("info").equals("OK"))
		{
			json.put("code", "00");
		}
		else{
			json.put("code", "01");
		}
		return json;
	}
	/**
	 * 根据关键字查询该城市地标----百度，暂时不用
	 * @param areaName
	 * @param city
	 * @return
	 */
	public static JSONObject pointSerch_baidu(String areaName,String city)
	{
		StringBuffer sb=new StringBuffer("http://api.map.baidu.com/place/v2/search?output=json");
		sb.append("&coord_type=bd09ll");
		sb.append("&ak="+ConstDefine.getBaiduAK());
		sb.append("&region="+city);
		sb.append("&query="+areaName);
		sb.append("&city_limit=true");
//		sb.append("&callback=showLocation");
		String res=HttpKit.get(sb.toString());
		
		return new JSONObject(res);
	}
	
	/**
	 * 根据坐标取地市
	 * @param point
	 * @return
	 */
	public static JSONObject getCityByPoint(String point)
	{
		JSONObject json=new JSONObject();
		json.put("code", "01");
		StringBuffer sb=new StringBuffer("http://api.map.baidu.com/reverse_geocoding/v3/?output=json");
		sb.append("&coordtype=gcj02ll");//使用火星坐标系解析
		sb.append("&ak="+ConstDefine.getBaiduAK());
		sb.append("&location="+point);
//		sb.append("&callback=showLocation");
		JSONObject bdres=new JSONObject(HttpKit.get(sb.toString()));
		System.out.println(bdres.toString());
		if(bdres.getInt("status")==0)
		{
			JSONObject detail=bdres.getJSONObject("result").getJSONObject("addressComponent");
			json.put("code", "00");
			json.put("province", detail.getString("province"));
			json.put("city", detail.getString("city"));
			json.put("area", detail.getString("district"));
			json.put("street", detail.getString("street"));
		}
		
		return json;
	}
	
	/**
	 * 根据位置名称获取百度坐标
	 * @param areaName
	 * @param city
	 */
	public static JSONObject getPointByAreaName(String areaName,String city)
	{
		JSONObject json_res=new JSONObject();
		StringBuffer sb=new StringBuffer("http://api.map.baidu.com/geocoding/v3/?output=json");
		sb.append("&address="+areaName);
		if(StrKit.notBlank(city))sb.append("&city="+city);
		sb.append("&ak="+ConstDefine.getBaiduAK());
//		sb.append("&callback=showLocation");
		String res=HttpKit.get(sb.toString());
		JSONObject json=new JSONObject(res);//根据名称取坐标
		if(json.getInt("status")==0)//如果取到坐标没问题
		{
			JSONObject location=json.getJSONObject("result").getJSONObject("location");
			String lng=location.getDouble("lng")+"";
			String lat=location.getDouble("lat")+"";
			json_res.put("lng", lng);
			json_res.put("lat", lat);
			JSONObject cityJson=getCityByPoint(lat+","+lng);//取地市
			if(cityJson.getInt("status")==0)
			{
				JSONObject json_city=cityJson.getJSONObject("result").getJSONObject("addressComponent");
				json_res.put("province", json_city.getString("province"));
				json_res.put("city", json_city.getString("city"));
				json_res.put("returnCode", "00");
			}
		}
		
		return json_res;
	}
	
	/**
	 * 84 to 火星坐标系 (GCJ-02)
	 * 
	 * @param lat
	 * @param lon
	 * @return
	 */
	public static Gps gps84_To_Gcj02(double lon, double lat) {
		if (outOfChina(lon, lat)) {
			return null;
		}
		double dLat = transformLat(lon - 105.0, lat - 35.0);
		double dLon = transformLon(lon - 105.0, lat - 35.0);
		double radLat = lat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		double mgLat = lat + dLat;
		double mgLon = lon + dLon;
		return new Gps(mgLon, mgLat);
	}
	/**
	 * 84 to 火星坐标系 (GCJ-02)
	 * 
	 * @param point lon,lat
	 * @return lon,lat
	 */
	public static String gps84_To_Gcj02(String point) {
		String[] points=point.split(",");
		double lon=Double.parseDouble(points[0]);
		double lat=Double.parseDouble(points[1]);
		
		if (outOfChina(lon, lat)) {
			return null;
		}
		double dLat = transformLat(lon - 105.0, lat - 35.0);
		double dLon = transformLon(lon - 105.0, lat - 35.0);
		double radLat = lat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		double mgLat = lat + dLat;
		double mgLon = lon + dLon;
		Gps gps=new Gps(mgLon, mgLat);
		return gps.getLontitude()+","+gps.getLatitude();
	}
	/**
	 * * 火星坐标系 (GCJ-02) to 84 * * @param lon * @param lat * @return
	 * */
	public static Gps gcj_To_Gps84(double lon, double lat) {
		Gps gps = transform(lon, lat);
		double lontitude = lon * 2 - gps.getLontitude();
		double latitude = lat * 2 - gps.getLatitude();
		return new Gps(lontitude, latitude);
	}
 
	/**
	 * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
	 * 
	 * @param gg_lat
	 * @param gg_lon
	 */
	public static Gps gcj02_To_Bd09(double gg_lon, double gg_lat) {
		double x = gg_lon, y = gg_lat;
		double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi);
		double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi);
		double bd_lon = z * Math.cos(theta) + 0.0065;
		double bd_lat = z * Math.sin(theta) + 0.006;
		return new Gps(bd_lon, bd_lat);
	}
 
	/**
	 * * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 * * 将 BD-09 坐标转换成GCJ-02 坐标 * * @param
	 * bd_lat * @param bd_lon * @return
	 */
	public static Gps bd09_To_Gcj02(double bd_lon, double bd_lat) {
		double x = bd_lon - 0.0065, y = bd_lat - 0.006;
		double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * pi);
		double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * pi);
		double gg_lon = z * Math.cos(theta);
		double gg_lat = z * Math.sin(theta);
		return new Gps(gg_lon, gg_lat);
	}
 
	/**
	 * (BD-09)-->84
	 * @param bd_lat
	 * @param bd_lon
	 * @return
	 */
	public static Gps bd09_To_Gps84(double bd_lon, double bd_lat) {
 
		Gps gcj02 = PositionUtil.bd09_To_Gcj02(bd_lat, bd_lon);
		Gps map84 = PositionUtil.gcj_To_Gps84(gcj02.getLatitude(),
				gcj02.getLontitude());
		return map84;
 
	}
 
	public static boolean outOfChina(double lon, double lat) {
		if (lon < 72.004 || lon > 137.8347)
			return true;
		if (lat < 0.8293 || lat > 55.8271)
			return true;
		return false;
	}
 
	public static Gps transform(double lon, double lat) {
		if (outOfChina(lon, lat)) {
			return new Gps(lat, lon);
		}
		double dLat = transformLat(lon - 105.0, lat - 35.0);
		double dLon = transformLon(lon - 105.0, lat - 35.0);
		double radLat = lat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		double mgLat = lat + dLat;
		double mgLon = lon + dLon;
		return new Gps(mgLon, mgLat);
	}
 
	public static double transformLat(double x, double y) {
		double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
				+ 0.2 * Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
		ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
		return ret;
	}
 
	public static double transformLon(double x, double y) {
		double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
				* Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
		ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
				* pi)) * 2.0 / 3.0;
		return ret;
	}
 
}
